package org.noootsab.gae.games.tzaar.model.game {
import com.adobe.serialization.json.JSON;

import mx.logging.ILogger;
import mx.logging.Log;

public class GameState {

    public static const CAPTURING_PHASE:uint = 0;
    public static const CAPTURING_OR_STRENGTHENING_PHASE:uint = 1;

    public var game:Game;
    public var currentPlayer:String;
    public var phase:uint;
    public var previousState:GameState;
    public var action:GameAction;
    public var winner:String;

    public function GameState(game:Game, currentPlayer:String, phase:uint, previousState:GameState, winner:String = null) {
        this.game = game;
        this.currentPlayer = currentPlayer;
        this.phase = phase;
        this.previousState = previousState;
        this.winner = winner;
    }

    public function setAction(action:GameAction):void {
        this.action = action;
    }

    public static function getStartedState(game:Game):GameState {
        return new GameState(game, game.white, CAPTURING_PHASE, null);
    }

    public static function getNextState(game:Game, previousState:GameState):GameState {
        if (previousState === null) {
            throw new Error("Previous State can't be null!")
        }
        if (previousState.action === null) {
            throw new Error("Can't go to the next State when no action has been taken at the previous state.")
        }
        var gameState:GameState;
        if (previousState.previousState === null) {
            //the previous state is then the 'start' state
            gameState = new GameState(game, game.black, CAPTURING_PHASE, previousState);
        } else {
            var previousPlayer:String = previousState.currentPlayer;
            var opponent:String = game.opponent(previousPlayer);

            var currentPlayer:String;
            var currentOpponent:String;
            var currentPhase:uint;
            if (previousState.phase === CAPTURING_PHASE) {
                currentPlayer = previousPlayer;
                currentOpponent = opponent;
                currentPhase = CAPTURING_OR_STRENGTHENING_PHASE;
            } else {
                currentPlayer = opponent;
                currentOpponent = previousPlayer;
                currentPhase = CAPTURING_PHASE;
            }

            var winner:String = isGameAboutToEnd(game, currentPlayer, currentOpponent);

            gameState = new GameState(game, currentPlayer, currentPhase, previousState, winner);

        }
        return gameState;
    }

    private static function isGameAboutToEnd(game:Game, currentPlayer:String, opponent:String):String {
        var blackPlayer:Boolean = game.isBlack(currentPlayer);

        var bc:BoardConfiguration = game.boardConfiguration;

        // check number of pieces left
        for (var c:uint = 0 ; c < 6 ; c++) {
            if (bc.piecesCount[c] === 0) {
                if (c < 3) {
                    if (blackPlayer) {
                        return opponent;
                    } else {
                        return currentPlayer;
                    }
                } else {
                    if (blackPlayer) {
                        return currentPlayer;
                    } else {
                        return opponent;
                    }
                }
            }
        }

        // check if at least on action is available for the current player
        var matrix:Array = bc.matrix;
        for (var i:uint = 0 ; i < matrix.length ; i++) {
            var a:Array = matrix[i];
            for (var j:uint = 0 ; j < a.length ; j++) {
                var p:Piece = a[j];
                if (p !== null) {
                    if (p.black === blackPlayer) {
                        var ns:Array = bc.getNeighbors(p.line, p.cell);
                        if (ns !== null && ns.length > 0) {
                            //there is at least one action available for current player
                            return null;
                        }
                    }
                }
            }
        }
        return opponent;
    }

    public static function getFinishedState(game:Game, previousState:GameState, winner:String):GameState {
        if (previousState.action === null) {
            throw new Error("Can't end the game when no action has been taken at the last state.")
        }
        if (winner === null) {
            throw new Error("No winner player has been specified... A tzaar game always end with a winner and a loser.")
        }
        return new GameState(game, game.white, CAPTURING_PHASE, previousState, winner);
    }

    public static function fromJSON(game:Game, json:*):GameState {
        var jsonState:Object;
        if (json is String) {
            jsonState = JSON.decode(json) as Object;
        } else if (json is Object) {
            jsonState = json;
        } else {
            throw new Error("Bad Json given");
        }

        var previous :GameState = null;
        if (jsonState.hasOwnProperty("previousState")) {
            previous = GameState.fromJSON(game, jsonState.previousState);
        }

        var winner:String = null;
        if (jsonState.hasOwnProperty("winner")) {
            winner = jsonState.winner as String;
        }

        var state:GameState = new GameState(game, jsonState.currentPlayer, jsonState.phase, previous, winner);

        if (jsonState.hasOwnProperty("action")) {
            state.setAction(GameAction.fromJSON(game, jsonState.action))
        }

        return state;
    }

    public static function toJSON(gameState:GameState):String {
        var json:String = "{";

        json += "\"currentPlayer\":\"" + gameState.currentPlayer + "\"";
        json += ",";

        json += "\"phase\":" + gameState.phase;

        if (gameState.previousState !== null) {
            json += ",";
            json += "\"previousState\":" + GameState.toJSON(gameState.previousState);
        }

        if (gameState.action !== null) {
            json += ",";
            json += "\"action\":" + GameAction.toJSON(gameState.action);
        }

        if (gameState.winner !== null) {
            json += ",";
            json += "\"winner\":\"" + gameState.winner + "\"";
        }

        json += "}";
        return json;
    }
}
}